#include "plane.h"
#include "vector.h"
#include "..\engine\error.h"
#include <math.h>

Planef::Planef(Vector3f &a, Vector3f &b, Vector3f &c)
{
	Vector3f	s = a - b; 
	Vector3f	t = a - c; 

	Vector3f::normalize(&s); 
	Vector3f::normalize(&t); 

	Vector3f::cross(&normal, &s, &t); 
	distance = -Vector3f::dot(&a, &normal); 
}
Planef::Planef(Vector3f& n, float d)
{
	normal = n;
	distance = d;
}

Planef::Planef(float nx, float ny, float nz, float d)
{
	normal.x = nx;
	normal.y = ny;
	normal.z = nz;
	distance = d;
}

Planef::Planef(Vector3f *pV)
{
	if(pV)
	{
		Vector3f	s = pV[0] - pV[1]; 
		Vector3f	t = pV[0] - pV[2]; 

		Vector3f::normalize(&s); 
		Vector3f::normalize(&t); 

		Vector3f::cross(&normal, &s, &t); 

		Vector3f::normalize(&normal); 

		distance = -Vector3f::dot(&pV[0], &normal); 
	}
}

void Planef::normalize(void)
{
	Vector3f::normalize(&normal);
}

/**************************************
 * Enables the client to determine onwhich
 * side of the specified plane, the specified
 * point existists
 **************************************/
Planef::Classification Planef::ClassifyPoint(Planef* pPlane, Vector3f* pPoint) {

#ifdef _DEBUG
	if(ISNULL(pPlane) || ISNULL(pPoint)) {
		EE_LOGERROR("Bad parameters.");
		return Planef::INTERSECTING;
	}
#endif

	const float k = Vector3f::dot(&pPlane->normal, pPoint);
	
	return (k > pPlane->distance) ? Planef::ABOVE : ( k < pPlane->distance ? Planef::BELOW : Planef::INTERSECTING );
}

/**************************************
 * Enables the client to determine onwhich
 * side of the specified plane, the specified
 * sphere existists
 **************************************/
Planef::Classification Planef::ClassifySphere(Planef* pPlane, Vector3f* pCenter, const float radius) {

#ifdef _DEBUG
	if(ISNULL(pPlane) || ISNULL(pCenter) || radius <= 0.0f) {
		EE_LOGERROR("Bad parameters.");
		return Planef::INTERSECTING;
	}
#endif

	const float k = Vector3f::dot(&pPlane->normal, pCenter);

	if(radius > k - pPlane->distance)
		return Planef::INTERSECTING;
	
	return k > 0 ? Planef::BELOW : Planef::ABOVE;
}

/**************************************
 * Enables the client to determine onwhich
 * side of the specified plane, the specified
 * sphere existists
 **************************************/
Planef::Classification Planef::ClassifySphere(Planef* pPlane, Spheref* pSphere) {

#ifdef _DEBUG
	if(ISNULL(pPlane) || ISNULL(pSphere) || pSphere->m_radius <= 0.0f) {
		EE_LOGERROR("Bad parameters.");
		return Planef::INTERSECTING;
	}
#endif

	const float k = Vector3f::dot(&pPlane->normal, &pSphere->m_center);

	if(pSphere->m_radius > k - pPlane->distance)
		return Planef::INTERSECTING;
	
	return k > 0 ? Planef::BELOW : Planef::ABOVE;
}

/**************************************
 * Enables the client to determine onwhich
 * side of the specified plane, the specified
 * sphere existists
 **************************************/
float Planef::Distance(Planef* pPlane, Vector3f* pPoint) {

#ifdef _DEBUG
	if(ISNULL(pPlane) || ISNULL(pPoint)) {
		EE_LOGERROR("Bad parameters.");
		return 0.0f;
	}
#endif

	const float offset = Vector3f::dot(&pPlane->normal, pPoint) - pPlane->distance;
	return fabs(offset);
}